<!doctype html>
<html>
	<head>
		<meta charset="utf-8"\>
		<title>Simulator</title>
		<link rel="stylesheet" type="text/css" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css">
		
	</head>
	<body>

	<div id="setting" class="row">
		<div id="application_generator" class="col-xs-6 col-md-6">
			<form id="generates">
				<div class="input-group">
					<span class="input-group-addon">Application number:</span>
					<input type="text" class="form-control" placeholder="" name="applicationNumber" value="6">
				</div>
				<div class="input-group">
					<span class="input-group-addon">Task number:</span>
					<input type="text" class="form-control" placeholder="" name="taskNumber" value="16">
					<span class="input-group-addon">+/-</span>
					<input type="text" class="form-control" placeholder="" name="taskNumberVarient" value="6">
				</div>
				<div class="input-group">
					<span class="input-group-addon">Task execution volume:</span>
					<input type="text" class="form-control" placeholder="task execution volume" name="executionVolume" value="128">
					<span class="input-group-addon">+/-</span>
					<input type="text" class="form-control" placeholder="task execution volume" name="executionVolumeVarient" value="32">
				</div>
				<div class="input-group">
					<span class="input-group-addon">CCR:</span>
					<input type="text" class="form-control" placeholder="CCR" name="CCR" value="0.005">
					<span class="input-group-addon">+/-</span>
					<input type="text" class="form-control" placeholder="CCR" name="CCRVarient" value="0.002">
				</div>
				<div class="input-group">
					<span class="input-group-addon">Task communication volume:</span>
					<input type="text" class="form-control" placeholder="task communication volume" name="communicationVolume" value="0.1">
					<span class="input-group-addon">+/-</span>
					<input type="text" class="form-control" placeholder="task communication volume" name="communicationVolumeVarient" value="0.002">
				</div>
				<div class="input-group">
					<span class="input-group-addon">Arrival rate:</span>
					<input type="text" class="form-control" placeholder="" name="arrivalRate" value="0.2">
					<span class="input-group-addon">+/-</span>
					<input type="text" class="form-control" placeholder="" name="arrivalRateVarient" value="0.2">
				</div>	
				<div class="input-group">
					<span class="input-group-addon">Application type:</span>
					<input type="text" class="form-control" placeholder="" name="type"  value="star">
				</div>			
				<input class="btn btn-default" type="submit" value="generate!">
				
			</form>
		</div>
		<div id="NoCBuilder" class="col-xs-6 col-md-6">
			<form id="builds">
				<div class="input-group">
					<input type="text" class="form-control" placeholder="width" name="width" value="8">
					<input type="text" class="form-control" placeholder="height" name="height" value="8">
					<input type="text" class="form-control" placeholder="length" name="ll" value="1">
					<input type="text" class="form-control" placeholder="execution speed" name="executionSpeed" value="10">
					<input type="text" class="form-control" placeholder="communication speed" name="communicationSpeed" value="1">
					<input type="text" class="form-control" placeholder="initial temperature" name="temperatureInit" value="60">
					<input type="text" class="form-control" placeholder="temperature threshold" name="temperatureThreshold" value="80">
					<input class="btn btn-default" type="submit" value="build!">
				</div>
			</form>
		</div>
	</div>

	<div id="running" class="row">
		<div id="applications" class="col-md-3">
			<button id="start_simulation">Simulate!</button>
			<div id="applications_display">
				
			</div>
		</div>
		<div id="NoC" class="col-md-6"></div>
		<div id="evaluation matrix" class="col-md-3">
			<div id="real_time" class="thumbnail">
				<h6>Real-time Performance Matrix</h6>
				<p>Max core temperature:</p>
				<p>Median core temperature: </p>
				<p>Available cores under thermal constraints: </p>
				<p>Available cores: </p>
				<p>Contiguous areas: </p>
				<p>Fragmentationess: </p>
			</div>
			
			<div id="finished" class="thumbnail">
				<h6>Finished Performance Matrix</h6>
				<p>Throuput: </p>
				<p>Average waiting time: </p>
				<p>Communication cost: </p>
			</div>
		</div>
		</div>
	</div>

	</body>
	<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.2/jquery.min.js"></script>
	<script src="http://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/js/bootstrap.min.js"></script>
	<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/two.js/0.6.0/two.min.js"></script>
	<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r76/three.min.js"></script>
	<script src="font.js"></script>
	<script type="text/javascript">

	$('#generates').submit(function(ev) {
	    ev.preventDefault(); // to stop the form from submitting
	    /* generatiron go here */
	    var applicationConfig = {
	    	applicationNumber : parseInt(document.forms["generates"].elements['applicationNumber'].value),
	    	taskNumber : parseInt(document.forms["generates"].elements['taskNumber'].value),
	    	taskNumberVarient : parseInt(document.forms["generates"].elements['taskNumberVarient'].value),
	    	executionVolume : parseFloat(document.forms["generates"].elements['executionVolume'].value),
	    	executionVolumeVarient : parseFloat(document.forms["generates"].elements['executionVolumeVarient'].value),
	    	CCR : parseFloat(document.forms["generates"].elements['CCR'].value),
	    	CCRVarient : parseFloat(document.forms["generates"].elements['CCRVarient'].value),
	    	communicationVolume : parseFloat(document.forms["generates"].elements['communicationVolume'].value),
	    	communicationVolumeVarient : parseFloat(document.forms["generates"].elements['communicationVolumeVarient'].value),
	    	arrivalRate : parseFloat(document.forms["generates"].elements['arrivalRate'].value),
	    	arrivalRateVarient : parseFloat(document.forms["generates"].elements['arrivalRateVarient'].value),
	    	type : document.forms["generates"].elements['type'].value
	    }

	   //console.log(applicationConfig);
	    /*
			var app = {
				id:appIndex,
				taskNum:applicationConfig.taskNumber,
				arrivalTime:Math.ceil(appIndex/applicationConfig.arrivalRate),
				tasks:[]
			}
			var task = {
						id:taskIndex,
						execution:applicationConfig.executionVolume,
						neibors:[]
			}
	    */ 
	    var applications = applicationGenerator(applicationConfig);
	    //console.log(applications);
	    var taskNumMax = 0;
		for(each in applications){
			if(applications[each].taskNum > taskNumMax){
				taskNumMax = applications[each].taskNum;
			}
		}

	    var two = new Two({width:taskNumMax*20,height:applications.length*taskNumMax*20}).appendTo(document.getElementById("applications_display"));
	    var center = {x:taskNumMax*10,y:0};
	    for(var index in applications){
	    	center.y += applications[index].taskNum*10;
	    	drawApplicaton(applications[index],center,two);
	    	center.y += applications[index].taskNum*10;
	    }
	    two.update();	
	    console.log(applications)
		localStorage.setItem("applications",JSON.stringify(applications));

		var xhr = new XMLHttpRequest();
		xhr.open("post", "/generates", true);
		xhr.setRequestHeader('Content-Type', 'application/json; charset=UTF-8');
		var applications = JSON.parse(localStorage.applications);
		xhr.send(JSON.stringify(applications));
	})

	
	var systemCubes=[];
	$('#builds').submit(function(ev){
		ev.preventDefault();
		var xhr = new XMLHttpRequest();
		xhr.open("post", "/builds", true);
		xhr.setRequestHeader('Content-Type', 'application/json; charset=UTF-8');

		var systemConfig = {
			width:parseInt(document.forms["builds"].elements['width'].value),
			height:parseInt(document.forms["builds"].elements['height'].value),
			length:parseInt(document.forms["builds"].elements['ll'].value),
			executionSpeed:parseFloat(document.forms["builds"].elements['executionSpeed'].value),
			communicationSpeed:parseFloat(document.forms["builds"].elements['communicationSpeed'].value),
			temperatureInit:parseFloat(document.forms["builds"].elements['temperatureInit'].value),
			temperatureThreshold:parseFloat(document.forms["builds"].elements['temperatureThreshold'].value)
		}
		// send the collected data as JSON
		//xhr.send(localStorage.applications);
		//console.log(systemConfig);
		localStorage.setItem("systemConfig",JSON.stringify(applications))
		xhr.send(JSON.stringify(systemConfig));


		var sceneWidth = 1000,sceneLength = 1000;
		var scene = new THREE.Scene();
		var camera = new THREE.PerspectiveCamera( 60, window.innerWidth / window.innerHeight, 1, 1000 );
		camera.position.z = 400;
		var renderer = new THREE.WebGLRenderer();
		renderer.setSize(window.innerWidth*0.5,window.innerHeight*0.5);
		document.getElementById('NoC').appendChild(renderer.domElement);


		var X=systemConfig.width,Y=systemConfig.height,Z=systemConfig.length;
		var sideLength = 10;
		var gap = 45;
		
		var thermalProfile = createXYZwithPattern(X,Y,Z,systemConfig.temperatureInit);
		//console.log(thermalProfile);
		var xRange = range(0,X,gap);
		var yRange = range(0,Y,gap);
		var zRange =range(0,Z,gap);

		var colorGap = (systemConfig.temperatureThreshold - systemConfig.temperatureInit)
		var cubeCnt = 0;
		for ( z in zRange){
			for( y in yRange){
				for( x in xRange){
					
					//console.log("x:" + xRange[x]+"y:"+yRange[y]+"z:"+zRange[z]);
					var geometry = new THREE.SphereGeometry( sideLength, sideLength, sideLength ); 
					var material = new THREE.MeshBasicMaterial( { color: new THREE.Color((thermalProfile[z][y][x]-systemConfig.temperatureInit)/colorGap,(systemConfig.temperatureThreshold-thermalProfile[z][y][x])/colorGap,0)}); 
					var cube = new THREE.Mesh( geometry, material );
					cube.position.set(xRange[x],yRange[y],zRange[z]);
					cube.setColor = function(cl){
						cube.material.color.set(cl);
					}
					systemCubes.push(cube);
					scene.add(systemCubes[cubeCnt]);
					cubeCnt++;
				}
			}
		}

		var cylinderXRangeX = range(0,X-2,gap);
		var cylinderYRangeX = range(0,Y,gap);
		var cylinderZRangeX = range(0,Z,gap);
		drawCommunication(cylinderXRangeX,cylinderYRangeX,cylinderZRangeX,new THREE.Vector3(0,0,1),1.57);

		var cylinderXRangeY = range(0,X,gap);
		var cylinderYRangeY = range(0,Y-2,gap);
		var cylinderZRangeY = range(0,Z,gap);
		drawCommunication(cylinderXRangeY,cylinderYRangeY,cylinderZRangeY,new THREE.Vector3(0,0,0),0);

		var cylinderXRangeZ = range(0,X,gap);
		var cylinderYRangeZ = range(0,Y,gap);
		var cylinderZRangeZ = range(0,Z-2,gap);
		drawCommunication(cylinderXRangeZ,cylinderYRangeZ,cylinderZRangeZ,new THREE.Vector3(1,0,0),1.57);


		animate();
		function animate(){
			requestAnimationFrame(animate);
			render();
		}

		function render(){
			var timer = Date.now() * 0.0001;

		    camera.position.x = Math.cos( timer ) * 100;
		    camera.position.y = Math.sin( timer ) * 100;

			renderer.render(scene,camera);
		}



		function drawCommunication(cylinderXRange,cylinderYRange,cylinderZRange,rotateVector,rotateAngle){
			for(var x in cylinderXRange){
				for(var y in cylinderYRange){
					for (var z in cylinderZRange){
						//console.log("x:" + x+"y:"+x+"z:"+z);
						var geometry = new THREE.CylinderGeometry(  5, 5,gap*2, 32 ); 
						var material = new THREE.MeshBasicMaterial( { color: 0x00FF00 } ); 
						var cylinder = new THREE.Mesh( geometry, material );
						cylinder.position.set(cylinderXRange[x],cylinderYRange[y],cylinderZRange[z]);
						scene.add( cylinder );
						cylinder.rotateOnAxis(rotateVector,rotateAngle);
						//show -= 0x0FF000;
						//radius += 1;
					}
				}
			}
		}

		function range (mean,count,step) {
			var result = [];
			if(count < 1){
				return result;
			}
			if(count%2 == 1){
				var meanIndex = Math.floor(count/2);
				result[meanIndex] = mean;
				for (var i = 1;i <= meanIndex;i++) {
					result[meanIndex - i] = -step*i + mean;
					result[meanIndex + i] = step*i + mean;
				};
			}else{
				var meanIndex = count/2;
				result[meanIndex] = step/2;
				result[meanIndex - 1] = -step/2;
				for(var i = 1;i <= meanIndex - 1;i++){
					result[meanIndex+i] = step/2 + step*i;
					result[meanIndex - 1 -i] = -step/2 - step*i;
				}
			}

		    return result;
		}

		function createXYZwithPattern(X,Y,Z,temperatureInit){
			var result=[];
			for(var l=0;l<Z;l++){
				var heightLine=[];
				for(var h=0;h<Y;h++){
					var widthLine = [];
					for(var w=0;w<X;w++){
							widthLine.push(temperatureInit);
					}
					heightLine.push(widthLine);
				}
				result.push(heightLine);
			}
			return result;
		}

	})
	
	


	function applicationGenerator(applicationConfig){
		var apps = [];
		for (var appIndex = 0;appIndex<applicationConfig.applicationNumber;appIndex++ ){
			var app = {
				id:appIndex,
				taskNum:applicationConfig.taskNumber + Math.floor(applicationConfig.taskNumberVarient*2*Math.random() - applicationConfig.taskNumberVarient),
				arrivalTime:Math.ceil(appIndex/applicationConfig.arrivalRate),
				tasks:[]
			}
			var ccr = applicationConfig.CCR +applicationConfig.CCRVarient*2*Math.random() - applicationConfig.CCRVarient
			for (var taskIndex = 0;taskIndex<applicationConfig.taskNumber;taskIndex++ ){
				var task = {
						id:taskIndex,
						execution:applicationConfig.executionVolume+ Math.floor(applicationConfig.executionVolumeVarient*2*Math.random() - applicationConfig.executionVolumeVarient),
						neibors:[]
					}
					var commuV = applicationConfig.communicationVolume + Math.floor(applicationConfig.communicationVolumeVarient*2*Math.random() - applicationConfig.communicationVolumeVarient)
				switch(applicationConfig.type){
					case "star":
						if(task.id == 0){
							task["neibors"].push(0);
							for (var neiIndex = 1;neiIndex<applicationConfig.taskNumber;neiIndex++ ){
								task["neibors"].push(-(commuV+ ccr*task.execution).toFixed(2))//.toFixed(2));
							}
						}else{
							task["neibors"][0] = -app.tasks[0]["neibors"][task.id];
							for (var neiIndex = 1;neiIndex<applicationConfig.taskNumber;neiIndex++ ){
								task["neibors"].push(0);
							}
						}
					break;
					default:
					break;
				}
				app["tasks"].push(task);
			}
			apps.push(app);
		}

		return apps;
	}

	function drawApplicaton(app,center,two){
		//var applicationDiv = document.createElement("div");
		var taskGroup = [];
		var taskNum = app.taskNum;
		var tasks = app.tasks;
		for(cnt in tasks){
			var task = tasks[cnt];
			var taskCenter = new Two.Vector(Math.cos(task.id/taskNum * 2* Math.PI)*taskNum*5,Math.sin(task.id/taskNum * 2* Math.PI)*taskNum*5);
			var taskCircle = two.makeCircle(taskCenter.x,taskCenter.y,16);
			var taskText = new Two.Text(task.execution+"",taskCenter.x,taskCenter.y);
			taskCircle.fill = "green";
			var neibors = task.neibors;
			var edgeGroup = [];
			for(cne in neibors){
				if(neibors[cne] < 0){
					var edgeLine = two.makeLine(taskCenter.x,taskCenter.y,Math.cos(cne/taskNum * 2* Math.PI)*taskNum*5,Math.sin(cne/taskNum * 2* Math.PI)*taskNum*5);
					var edgeText = new Two.Text((-neibors[cne])+"",(taskCenter.x +Math.cos(cne/taskNum * 2* Math.PI)*taskNum*5)*0.5 ,(taskCenter.y+Math.sin(cne/taskNum * 2* Math.PI)*taskNum*5)*0.5);
					edgeLine.stroke = 'orangered';
					edgeLine.linewidth = 1;
					var edgeSingle = two.makeGroup(edgeLine,edgeText)
					edgeGroup.push(edgeSingle);

				}
			}
			var edges = two.makeGroup(edgeGroup);
			var taskSingle = two.makeGroup(taskCircle,taskText,edges);
			taskGroup.push(taskSingle);
		}

		var applicationSingle = two.makeGroup(taskGroup);
		applicationSingle.translation.set(center.x,center.y);
		
	}

	$('#start_simulation').click(function(ev){
			var xhr = new XMLHttpRequest();
			xhr.open("post", "/simulates", true);
			xhr.send();
			xhr.onreadystatechange = function() {
			    if (xhr.readyState == 4 && xhr.status == 200) {
			      console.log(xhr.responseText);
			      var ws = new WebSocket('ws://localhost:8080');
					ws.onmessage = function(message){
						//drawNoC(X,Y,Z,gap,sideLength,message.thermalProfile);
						var messageData = JSON.parse(message.data);
						console.log(messageData.taskProfile);
						message['taskProfile'] = []
						message['thermalProfile'] = [60,62,66,63,60,62,78,63,60,62,66,63,60,62,66,63,60,62,66,63,60,62,66,63,60,62,66,63,60,62,66,63,60,78,66,63,60,62,66,63,60,62,66,63,60,62,66,63,60,62,66,63,60,62,66,63,60,62,66,63,60,62,66,63]
						//updateSystem(message);
						message['applicationStatus'] = {
							waiting:[12,13,14,15,16],
							running:[0,1,2,3]
						}
						updateSystem(message);
					}
				}
			};
		})

	function updateSystem(message){
		var systemConfig = JSON.parse(localStorage.systemConfig);
		var thermalProfile = message.thermalProfile;
		var colorGap = 20;
		for(t in thermalProfile){
			systemCubes[t].setColor(new THREE.Color((thermalProfile[t]-systemConfig.temperatureInit)/colorGap,(systemConfig.temperatureThreshold-thermalProfile[t])/colorGap,0))
		}
	}
	</script>
	
</html>
